#ifndef __RECORD_H__
#define __RECORD_H__

#include <pthread.h>

#define RECORD_CONFIG_FILE       "/tmp/record.conf"
#define FILE_MAX_SIZE	        (300*1024*1024)

#define RSC_REC_MAX_CHN 4

/**************************** DataType Declarations *************************/
enum record_codec_format
{
	REC_CODEC_H264,
	REC_CODEC_MJPEG,
	REC_CODEC_AAC,
	REC_CODEC_G711A,
	REC_CODEC_G711U,
	REC_CODEC_PCM_ALAW,
	REC_CODEC_MAX
};
enum record_pack_format
{
	REC_PACK_AVI,
	REC_PACK_WAV,
	REC_PACK_MP3,
	REC_PACK_MAV,
	REC_PACK_RAW,
	REC_PACK_MAX
};
enum record_mode
{
	REC_MODE_UNDEF = 0,
	REC_MODE_AUTO, /* record when poweroff */
	REC_MODE_TIMER, /* timing record,assign start and end time */
	REC_MODE_EVENT, /* event trigger record,such open-door ,alarm event */
	REC_MODE_CYCLE, /* record plan mode,day,week,month or year plan */
};

enum  record_sink_type
{
	REC_SINK_VAMIX,
	REC_SINK_VIDEO,
	REC_SINK_AUDIO,
	REC_SINK_MAX
};
enum record_sink_subtype 
{
	REC_DTYPE_VIDEO,
	REC_DTYPE_AUDIO,
	REC_DTYPE_META,
	REC_DTYPE_MAX
};

enum record_status_machine
{
	REC_STAT_INIT,
	REC_STAT_CHECK, /* check params */
	REC_STAT_PREPARE,
	REC_STAT_WRITE,
	REC_STAT_FINI,
	REC_STAT_EXIT, /* exit record routine */
};

enum record_audio_solo
{
	REC_AUDIO_SOLO_OFF = 0,
	REC_AUDIO_SOLO_FAKE,
	REC_AUDIO_SOLO_REAL
};

typedef struct record_mode_param
{
	time_t timer_start; 
	time_t timer_end;
	int event_trigger;/* set to 1 when event happen */
	int event_time; /* event record time length,unit second */
	char event_desc[16];/* event description ,such as "alarm" */
}st_rec_mode_param;

typedef struct record_media_param
{
	/** video param */
	unsigned int video_cbr; /** cbr: 1, vbr: 0 */
	unsigned int video_bitrate;
	unsigned int video_framerate;
	unsigned int video_gop;
	unsigned int video_codec; /* see enum record_codec_format */
	unsigned int video_width;
	unsigned int video_height;
	unsigned int pic_level; /* picture level: 1-5, low to high */
	/** audio param */
	unsigned int audio_sample_fmt; 
	unsigned int audio_sample_rate; /* unit is HZ  */
	unsigned int audio_channels; /* perhaps value: 1,2,3 */
	unsigned int audio_bitrate;
	unsigned int audio_codec; /* see enum record_codec_format */
}st_rsc_rec_media;

typedef struct record_control_param
{
	int on;
	int file_time; /* record file time ,unit is second */
	int file_pack ;/* pack format,such avi */
	/* filename format string,such as 'YYYYMMDD/hhmmss_nn.avi' */
	char file_format[64];

	int audio_on;/* whether to record audio */
	int audio_solo;/* whether to record audio to a solo file */
	/* audio solo file time when @audio_solo is on,unit is second */
	int audio_time;
	/* audio pack format when @audio_solo is on,such wav */
	int audio_pack; 

	int chn_temp;/* whether channel record valid is temporary or persistent */
	int chn_suffix_start; /* record file channel suffix start id,-1 -- no suffix */
	
	int mode;
	/* mode description,such as 'auto','event','cycle' .etc */
	char mode_desc[16]; 
	st_rec_mode_param mode_param;
}st_rsc_rec_ctrl;

/* frame data structure to record */
struct record_frame_info
{
	unsigned char *addr;
	unsigned int size; /* addr availabe size */
	unsigned int len; /* frame length */
	unsigned long pts;
	unsigned int flag;
	int index;/* frame index, -1 is invalid */ 
};
typedef struct record_data_source
{
	/** data source */
	int chn; /* every channel has a data source for each data-type */
	int parallel; /* if use parallel record method (multi-pthread) */
	unsigned char *video_ds[RSC_REC_MAX_CHN];
	unsigned char *audio_ds[RSC_REC_MAX_CHN*2]; /// for video-inter & audio only
	unsigned char *meta_ds[RSC_REC_MAX_CHN];
	/** callback functions */
	int (*preprocess[REC_DTYPE_MAX])(struct record_frame_info *frame,unsigned char *source);
	int (*postprocess[REC_DTYPE_MAX])(unsigned char *outpool,struct record_frame_info *frame);
}st_rsc_rec_source;

typedef void* RSC_SINK_HANDLE;
struct rsc_sink_cfg
{
	int chn;
	st_rsc_rec_media mparam;
	void *user_data;
	int user_len;
};
typedef struct record_data_sink
{
	RSC_SINK_HANDLE (*init_sink)(const char *sink_name,int sink_type,struct rsc_sink_cfg *sink_cfg);
	int (*fill_sink)(RSC_SINK_HANDLE sink_handle,int subtype,struct record_frame_info *frame);
	int (*exit_sink)(RSC_SINK_HANDLE sink_handle);
}st_rsc_rec_sink;

struct rsc_record_param
{
	st_rsc_rec_media media;
	st_rsc_rec_ctrl  control;
	st_rsc_rec_source  source;
	st_rsc_rec_sink  sink;
};

struct rsc_channel_param
{
	int  valid; /** set true to use channel params,default false */
	int  chn;
	st_rsc_rec_media media;
	st_rsc_rec_ctrl  control;
};


/**
 * if record is on or off
 * @ret return true if on,or false if off
 */
extern int is_record(void);
/**
 * set record status flag whether indicates sd card is ok 
 * @param[in] flag on or off
 * @ret return true 
 */
extern int rsc_set_record(int flag);
/**
 * get record status flag whether indicates sd card is ok 
 * @ret return flag 
 */
extern int rsc_get_record(void);

/**
 * start assigned channel record or all channels record
 *
 * @param[in] chn assigned channel to start record,
 * 	chn = RSC_REC_MAX_CHN indicates start all channels record
 * @ret 0 if success,-1 if fail
 */
extern int rsc_start_record(int chn);

/**
 * stop assigned channel record or all channels record
 *
 * @param[in] chn assigned channel to stop record
 * 	chn = RSC_REC_MAX_CHN indicates stop all channels record
 * @ret 0 if success,-1 if fail
 */
extern int rsc_stop_record(int chn);

/**
 * get record params 
 * @param[in,out] param record parameter to store
 * @ret -1 if fail, 0 if success, 1 when read fail but use default.
 */
extern int rsc_get_rec_params(struct rsc_record_param *param);

/**
 * set record params to config file 
 *
 * if only change one key-value in params, you should call rsc_get_rec_params
 * first to get all params and then modify the kee-value,last call this api
 * to save the modified record params.
 *
 * @param[in] param record parameter to save 
 * @ret -1 if fail, 0 if success.
 */
extern int rsc_set_rec_params(struct rsc_record_param *param);

/**
 * set channel record params 
 *
 * if only change one key-value in params, you should call rsc_get_rec_params
 * first to get all params and then modify the kee-value,last call this api
 * to save the modified record params.
 *
 * you need to fill param->valid & param->chn member to correct value.
 * 	1. param->valid = 1 ---> enable <param->chn> channel record params
 * 		you need to fill param other member.
 * 	2. param->valid = 0 ---> disable <param->chn> channel record params
 * 		the other member is ignored at this value.
 *
 * @param[in] param channel record parameter to save 
 * @ret -1 if fail, 0 if success.
 */
extern int rsc_set_chn_params(struct rsc_channel_param *param);
extern int rsc_get_chn_params(struct rsc_channel_param *param);

/**
 * record init api that finish essential works to prepare record.
 *
 * you should call it before all other record apis.
 * @param[in] source record data source config params to init record env.
 * @param[in] sink record data sink config params to init record env.
 * @ret return 0 if ok, retur -1 if source is null.
 */
//extern int rsc_init_record(struct record_data_source* source,struct record_data_sink *sink);
extern int rsc_init_record(struct rsc_record_param *defcfg);

/**
 * record handle works to process record.
 *
 * you should call it after rsc_init_record.
 * @ret return channels number that has started record ok,
 * @note return value should be saved to pass in rsc_exit_record.
 * @see rsc_exit_record
 */
extern int rsc_handle_record(void);

/**
 * record exit api that reclaim resource and release work.
 *
 * you should call it after doesnot need record,and after call it you 
 * cannot call any RSC record apis.
 *
 * @param[in] chns_ok  the rsc_init_record return value
 * @see rsc_init_record
 */
extern void rsc_exit_record(int chns_ok);

/**
 * start audio solo record
 * @param[in] chn the assigned channel,= RSC_REC_MAX_CHN indicates all chns
 * @param[in] time record time length,unit is second, 0 - use last time value
 * @param[in] user_data extral user data to write into audio record file,if is
 * NULL, use last data.
 * @param[in] len the data length of user defined data
 */
extern int rsc_start_audio(int chn, int time/*unit:s*/, void *user_data,int len);

/**
 * stop audio solo record
 * @param[in] chn the assigned channel,= RSC_REC_MAX_CHN indicates all chns
 * @param[in] user_data extral user data to write into audio record file,if is
 * NULL, use last data.
 * @param[in] len the data length of user defined data
 */
extern int rsc_stop_audio(int chn, void *user_data,int len);

/**
 * whether to record audio and to put audio venc data to channel 0~3
 * @ret return true or false
 */
extern int is_audio_record(void);

/**
 * whether to record audio to a solo file and put
 * audio venc data to channel 4~7
 * @ret return true or false
 */
extern int is_audio_solo(void);

/**
 * get current record directory name
 * @param[in,out] dir current record directory name
 * @param[in] len avaliable dir buffer length to use
 * @ret 0 if success, or -1 if error happens.
 */
extern int rsc_get_cur_recdir(char dir[],int len);

/**
 * get current record file absolute path name
 * @param[in,out] fname current record file names
 * @param[in] len the file numbers,should > 2*RSC_REC_MAX_CHN
 * @ret 0 if success, or -1 if error happens.
 */
extern int rsc_get_recording_filename(char fname[][128],int len);

#endif

